﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using ImageConverter.Utils;
using SevenZip;

namespace ImageConverter.Data.Containers
{
    public class SevenZipReader : IEntryReader
    {
        #region IEntryReader Members

        public event OnEntryReadHandler OnEntryRead;

        public event OnEntryReadErrorHandler OnEntryReadError;

        public bool ValidateEntries(string fileName)
        {
            bool result = false;

            if (File.Exists(fileName))
            {
                using (SevenZipExtractor extractor = new SevenZipExtractor(fileName))
                {
                    try
                    {
                        result = extractor.ArchiveFileData.Count > 0;
                    }
                    catch (Exception ex) { }
                }
            }

            return result;
        }

        public ContainerResult ExtractEntries(string fileName, CancellationToken cancellationToken, PauseToken pauseToken)
        {
            ContainerResult result = new ContainerResult();

            using (SevenZipExtractor extractor = new SevenZipExtractor(fileName))
            {
                try
                {
                    foreach (var aName in extractor.ArchiveFileNames)
                    {
                        while (pauseToken.IsPaused && !cancellationToken.IsCancellationRequested)
                        {
                            Thread.Sleep(200);
                        }

                        if (cancellationToken.IsCancellationRequested)
                        {
                            return new ContainerResult()
                            {
                                IsCompleted = true
                            };
                        }

                        var shortName = Path.GetFileName(aName);

                        if (!String.IsNullOrEmpty(shortName) && !HasEmptyExtensions(aName) && !NonImageExtension(aName))
                        {
                            using (MemoryStream stream = new MemoryStream())
                            {
                                try
                                {
                                    extractor.ExtractFile(aName, stream);
                                    stream.Seek(0, SeekOrigin.Begin);

                                    if (OnEntryRead != null)
                                        OnEntryRead(new EntryData()
                                        {
                                            ByteData = stream.GetBuffer(),
                                            FileName = Path.GetFileName(shortName)
                                        });
                                }
                                catch (Exception ex)
                                {
                                    if (OnEntryReadError != null)
                                        OnEntryReadError(shortName, ex);
                                }
                            }
                        }
                    }

                    result.IsCompleted = true;
                }
                catch (Exception ax)
                {
                    result.IsError = true;
                    result.IsCompleted = false;
                    result.ErrorValue = ax;
                }
            }

            return result;
        }

        public IEnumerable<string> GetArchiveEntries(string fileName)
        {
            IEnumerable<string> result = new List<string>();

            using (SevenZipExtractor extractor = new SevenZipExtractor(fileName))
            {
                result = extractor.ArchiveFileNames.
                    Where(a => !HasEmptyExtensions(a) && !NonImageExtension(a)).
                    Select(a => Path.GetFileName(a));
            }

            return result;
        }

        private bool HasEmptyExtensions(string fullName)
        {
            return String.IsNullOrWhiteSpace(Path.GetExtension(fullName));
        }

        private bool NonImageExtension(string fullName)
        {
            var extension = Path.GetExtension(fullName);
            return nonImageExtensions.Contains(Path.GetExtension(fullName));
        }

        #endregion

        private static string[] nonImageExtensions = new string[] { ".db", ".txt" };
    }
}
